local Signal = require"ecs.signal"

local mt = {}
mt.__index = mt

function mt.New(cls, componentNames)
    local self = setmetatable({}, cls)
    self._componentNames = componentNames
    self._entities = {}
    self.entityAdded = Signal:New()
    self.entityRemoved = Signal:New()
    return self
end

function mt:getEntities()
    local entities = {}
    for id,entity in pairs(self._entities) do
        table.insert(entities, entity)
    end
    return entities
end

function mt:_matchEntity(entity)
    local names = self._componentNames
    for idx,name in ipairs(names) do
        if not entity:hasComponent(name) then
            return false
        end
    end
    return true
end

function mt:addEntityIfMatch(entity)
    if not self._entities[entity.id] and self:_matchEntity(entity) then
        self._entities[entity.id] = entity
        self.entityAdded:emit(entity)
    end
end

function mt:removeEntity(entity)
    if self._entities[entity.id] then
        self._entities[entity.id] = nil
        self.entityRemoved:emit(entity)
    end
end

function mt:onComponentAdded(entity, componentName)
    self:addEntityIfMatch(entity)
end

function mt:onComponentRemoved(entity, componentName)
    if not self._entities[entity.id] then return end
    local names = self._componentNames
    for idx,name in ipairs(names) do
        if name == componentName then
            self._entities[entity.id] = nil
            self.entityRemoved:emit(entity)
        end
    end
end

return mt
